package com.chandon.juc.thread_communication.SyncContainer;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 使用Conditon改造同步容器
 * 可以将Condition看作对线程的分组
 * Condition的本质是等待队列
 *
 * @author Dong
 */

public class SyncContainerUseCondition<T> {

	private final LinkedList<T> list = new LinkedList<>();

	private final int maxSize = 10;

	private int count = 0;

	private ReentrantLock lock = new ReentrantLock();

	/* 生产者线程分组 */
	Condition producerCondition = lock.newCondition();

	/* 消费者线程分组 */
	Condition consumerCondition = lock.newCondition();


	public void put(T t) {

		try {

			lock.lock();

			while (list.size() == maxSize) {
				producerCondition.await();
			}

			list.add(t);
			count++;
			/* 当容器内size=0时，消费者会阻塞，所以这里添加元素后通知消费者进行消费 */
			consumerCondition.signalAll();
			lock.unlock();

		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}

	public T get() {
		try {

			lock.lock();

			if (list.size() == 0) {
				consumerCondition.await();
			}

			T t = list.removeFirst();

			count--;
			/* 当容器内的元素数量已经达到最大时生产者阻塞，所以容器有元素空缺时通知生产者生产 */
			producerCondition.signalAll();
			lock.unlock();

			return t;

		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static void main(String[] args) {

		SyncContainerUseCondition<Object> container = new SyncContainerUseCondition<>();

		/* 生产者 */
		for (int i = 0; i < 2; i++) {

			new Thread(() -> {
				for (int j = 0; j < 50; j++) {
					container.put(Thread.currentThread().getName() + "-" + j);
				}

			}, "p:" + i).start();
		}

		/* 消费者 */
		for (int i = 0; i < 10; i++) {
			new Thread(() -> {
				for (int j = 0; j < 10; j++) {
					System.out.println(Thread.currentThread().getName() + "-" + container.get());
				}

			}, "c" + i).start();
		}
	}


}
